home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Exec_Dev / fms.c < prev    next >
C/C++ Source or Header  |  1994-02-01  |  11KB  |  522 lines

  1.  
  2. /*
  3.  *  FMS.C
  4.  *
  5.  *  File Disk Device (fmsdisk.device)
  6.  *
  7.  *  Simulates a trackdisk by using a large file to hold the 'blocks'.
  8.  */
  9.  
  10. #include "defs.h"
  11.  
  12. Prototype DevCall NDev *DevInit(register __a0 APTR);
  13. Prototype DevCall NDev *DevOpen(register __d0 long, register __a1 IOB *, register __d1 long);
  14. Prototype APTR DevExpunge(void);
  15. Prototype APTR DevClose(register __a1 IOB *);
  16. Prototype APTR DevReserved(void);
  17. Prototype void DevBeginIO(register __a1 IOB *iob);
  18. Prototype void DevAbortIO(register __a1 IOB *iob);
  19. Prototype void SynchroMsg(UWORD, NDUnit *);
  20. Prototype __geta4 void CoProc(void);
  21. Prototype void ExtendSize(NDUnit *, long);
  22. Prototype void FlushCache(void);
  23. Prototype void GetUnitName(int, char *);
  24.  
  25. extern struct Library *SysBase;
  26. struct DosLibrary *DOSBase    = NULL;
  27.  
  28. NDev *DevBase;
  29. APTR DevSegment;
  30. PORT *FProc;
  31. PORT FPort;
  32.  
  33. #ifdef DEBUG
  34. long DbFH;
  35. #endif
  36.  
  37. NDUnit *CacheUnit;
  38. long    CacheLen;
  39. char    CacheBuf[32768];    /*    32K buffer  */
  40.  
  41. /*
  42.  *  Init, segment in A0 (registered args), arg must be declared as a pointer
  43.  */
  44.  
  45. DevCall
  46. NDev *
  47. DevInit(register __a0 APTR seg)
  48. {
  49.     static func_ptr DevVectors[] = {
  50.     (func_ptr)DevOpen,
  51.     (func_ptr)DevClose,
  52.     (func_ptr)DevExpunge,
  53.     (func_ptr)DevReserved,
  54.     (func_ptr)DevBeginIO,
  55.     (func_ptr)DevAbortIO,
  56.     (func_ptr)-1
  57.     };
  58.     NDev *db;
  59.  
  60.     DevBase = db = (NDev *)MakeLibrary((long **)DevVectors,NULL,NULL,sizeof(NDev),NULL);
  61.     db->Lib.lib_Node.ln_Type = NT_DEVICE;
  62.     db->Lib.lib_Node.ln_Name = DeviceName;
  63.     db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
  64.     db->Lib.lib_Version = 1;
  65.     db->Lib.lib_IdString= (APTR)IdString;
  66.  
  67.     DevSegment = seg;
  68.     AddDevice((DEV *)db);
  69.     return(db);
  70. }
  71.  
  72. /*
  73.  *  open device
  74.  *
  75.  *    unitnum:    D0
  76.  *    iob:        A1
  77.  *    flags:        D1
  78.  *
  79.  *  have dummy pointer before iob so iob gets assigned A1 instead of A0
  80.  *  for registered args interface.
  81.  */
  82.  
  83. DevCall
  84. NDev *
  85. DevOpen(register __d0 long unitnum,
  86.     register __a1 IOB *iob,
  87.     register __d1 long flags
  88.        )
  89. {
  90.     NDev *nd = DevBase;
  91.     NDUnit *unit = &nd->Unit[unitnum];
  92.  
  93.     if (++nd->Lib.lib_OpenCnt == 1) {
  94.     FProc = CreateProc("FMS-Dummy", 0, (long)DUMmySeg >> 2, 8192);
  95.     FPort.mp_SigBit = SIGBREAKB_CTRL_D;    /*  port init */
  96.     FPort.mp_SigTask= FProc->mp_SigTask;
  97.     FPort.mp_Flags = PA_SIGNAL;
  98.     NewList(&FPort.mp_MsgList);
  99.     }
  100.  
  101.     if (++unit->OpenCnt == 1)
  102.     SynchroMsg(CMD_OPENUNIT, unit);
  103.  
  104.     nd->Lib.lib_Flags &= ~LIBF_DELEXP;
  105.     iob->io_Unit = (struct Unit *)unit;
  106.     iob->io_Error = 0;
  107.     return(nd);
  108. }
  109.  
  110. /*
  111.  *  expunge device, no arguments
  112.  */
  113.  
  114. APTR
  115. DevExpunge(void)
  116. {
  117.     NDev *nd = DevBase;
  118.     APTR dseg = DevSegment;
  119.  
  120.     if (dseg == NULL)
  121.     Alert(24);
  122.     if (nd->Lib.lib_OpenCnt) {
  123.     nd->Lib.lib_Flags |= LIBF_DELEXP;
  124.     return(NULL);
  125.     }
  126.     Remove((NODE *)nd);
  127.     FreeMem((char *)nd - nd->Lib.lib_NegSize, nd->Lib.lib_NegSize + nd->Lib.lib_PosSize);
  128.     ADevExpunge();
  129.     return(dseg);
  130. }
  131.  
  132. /*
  133.  *  device close.  Dummy pointer before iob so iob gets assigned A1
  134.  *
  135.  *    iob:    A1
  136.  */
  137.  
  138. DevCall
  139. APTR
  140. DevClose(register __a1 IOB *iob)
  141. {
  142.     NDev *nd = DevBase;
  143.  
  144.     {
  145.     NDUnit *unit = (NDUnit *)iob->io_Unit;
  146.     if (unit->OpenCnt && --unit->OpenCnt == 0)
  147.         SynchroMsg(CMD_CLOSEUNIT, unit);
  148.     }
  149.  
  150.     if (nd->Lib.lib_OpenCnt && --nd->Lib.lib_OpenCnt)
  151.     return(NULL);
  152.     if (FProc) {
  153.     SynchroMsg(CMD_KILLPROC, NULL);
  154.     FProc = NULL;
  155.     }
  156.     if (nd->Lib.lib_Flags & LIBF_DELEXP)
  157.     return(DevExpunge());
  158.     /*
  159.      *    close down resources
  160.      */
  161.     return(NULL);
  162. }
  163.  
  164. DevCall
  165. APTR
  166. DevReserved(void)
  167. {
  168.     return((APTR)0);
  169. }
  170.  
  171. DevCall
  172. void
  173. DevBeginIO(register __a1 IOB *iob)
  174. {
  175.     /*NDev *nd = DevBase;*/
  176.  
  177.     iob->io_Error = 0;
  178.     iob->io_Actual = 0;
  179.  
  180.     switch(iob->io_Command & ~TDF_EXTCOM) {
  181.     case CMD_INVALID:
  182.     iob->io_Error = IOERR_NOCMD;
  183.     break;
  184.     case CMD_RESET:
  185.     break;
  186.     case CMD_READ:
  187.     PutMsg(&FPort, &iob->io_Message);
  188.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  189.     iob = NULL;
  190.     break;
  191.     case CMD_WRITE:
  192.     PutMsg(&FPort, &iob->io_Message);
  193.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  194.     iob = NULL;
  195.     break;
  196.     case CMD_UPDATE:
  197.     PutMsg(&FPort, &iob->io_Message);
  198.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  199.     iob = NULL;
  200.     break;
  201.     case CMD_CLEAR:
  202.     break;
  203.     case CMD_STOP:
  204.     break;
  205.     case CMD_START:
  206.     break;
  207.     case CMD_FLUSH:
  208.     break;
  209.     case TD_MOTOR:        /*    motor,    no action   */
  210.     case TD_SEEK:        /*    seek,    no action   */
  211.     break;
  212.     case TD_FORMAT:        /*    format            */
  213.     PutMsg(&FPort, &iob->io_Message);
  214.     iob->io_Flags &= ~IOF_QUICK;    /*  not quick */
  215.     iob = NULL;
  216.     break;
  217.     case TD_REMOVE:        /*    not supported        */
  218.     iob->io_Error = IOERR_NOCMD;
  219.     break;
  220.     case TD_CHANGENUM:        /*    change count never changes  */
  221.     iob->io_Actual = 1;
  222.     break;
  223.     case TD_CHANGESTATE:    /*    0=disk in drive     */
  224.     iob->io_Actual = 0;
  225.     break;
  226.     case TD_PROTSTATUS:     /*    io_Actual -> 0 (rw) */
  227.     iob->io_Actual = 0;
  228.     break;
  229.     case TD_RAWREAD:        /*    not supported        */
  230.     case TD_RAWWRITE:
  231.     iob->io_Error = IOERR_NOCMD;
  232.     break;
  233.     case TD_GETDRIVETYPE:   /*    drive type?        */
  234.     iob->io_Actual = 0;
  235.     break;
  236.     case TD_GETNUMTRACKS:
  237.     iob->io_Actual = 0; /*    # of tracks?        */
  238.     break;
  239.     case TD_ADDCHANGEINT:   /*    action never taken  */
  240.     case TD_REMCHANGEINT:
  241.     break;
  242.     default:
  243.     iob->io_Error = IOERR_NOCMD;
  244.     break;
  245.     }
  246.     if (iob) {
  247.     if ((iob->io_Flags & IOF_QUICK) == 0)
  248.         ReplyMsg((MSG *)iob);
  249.     }
  250. }
  251.  
  252. DevCall
  253. void
  254. DevAbortIO(register __a1 IOB *iob)
  255. {
  256.  
  257. }
  258.  
  259.  
  260. /*
  261.  *  Server communications.  If we run out of memory, well, we retry
  262.  *  until memory is available.
  263.  */
  264.  
  265. void
  266. SynchroMsg(cmd, unit)
  267. UWORD cmd;
  268. NDUnit *unit;
  269. {
  270.     IOB Iob;
  271.  
  272.     do {
  273.     Iob.io_Message.mn_ReplyPort = CreatePort(NULL, 0);
  274.     Iob.io_Command = cmd;
  275.     Iob.io_Unit = (struct Unit *)unit;
  276.     } while (Iob.io_Message.mn_ReplyPort == NULL);
  277.  
  278.     PutMsg(&FPort, &Iob.io_Message);
  279.     WaitPort(Iob.io_Message.mn_ReplyPort);
  280.     DeletePort(Iob.io_Message.mn_ReplyPort);
  281. }
  282.  
  283. /*
  284.  *    SERVER SIDE (IS A PROCESS)
  285.  *
  286.  *    File name is:
  287.  */
  288.  
  289. __geta4 void
  290. CoProc(void)
  291. {
  292.     IOB *iob;
  293.     NDUnit *unit;
  294.     char buf[128];
  295.     char notdone = 1;
  296.  
  297.     Wait(SIGBREAKF_CTRL_D);     /*  wait for port init  */
  298.  
  299.     while (notdone) {
  300.     WaitPort(&FPort);
  301.     while (iob = (IOB *)GetMsg(&FPort)) {
  302.         unit = (NDUnit *)iob->io_Unit;
  303.  
  304. #ifdef DEBUG
  305.         if (DbFH) {
  306.         sprintf(buf, "Cmd %08lx/%04x @ %08lx Buf %08lx %04x\n",
  307.             unit, iob->io_Command, iob->io_Offset, iob->io_Data, iob->io_Length
  308.         );
  309.         Write(DbFH, buf, strlen(buf));
  310.         }
  311. #endif
  312.         /*
  313.          *    cache (increase OFS throughput)
  314.          */
  315.  
  316.         if (CacheLen && (iob->io_Command & ~TDF_EXTCOM) != CMD_WRITE)
  317.         FlushCache();
  318.  
  319.         switch(iob->io_Command & ~TDF_EXTCOM) {
  320.         case CMD_OPENUNIT:
  321.         GetUnitName(unit - &DevBase->Unit[0], buf);
  322.         unit->Fh = Open(buf, 1005);
  323.         if (unit->Fh == NULL) {
  324.             unit->Fh = Open(buf, 1006);
  325.             unit->Extended = 1;
  326.         }
  327. #ifdef DEBUG
  328.         if (DbFH) {
  329.             Write(DbFH, "OPEN ", 5);
  330.             Write(DbFH, buf, strlen(buf));
  331.             Write(DbFH, "\n", 1);
  332.         }
  333. #endif
  334.         if (unit->Fh) {
  335.             Seek(unit->Fh, 0L, 1);
  336.             unit->Size = Seek(unit->Fh, 0L, -1);
  337.         }
  338.         unit->Pos = -1;
  339.         break;
  340.         case CMD_CLOSEUNIT:
  341.         if (unit->Fh) {
  342.             Close(unit->Fh);
  343.             unit->Fh = NULL;
  344.         }
  345.         break;
  346.         case CMD_KILLPROC:
  347.         notdone = 0;
  348.         break;
  349.         case CMD_READ:
  350.         if (unit->Fh == NULL)
  351.             break;
  352.         if (iob->io_Offset + iob->io_Length > unit->Size)
  353.             ExtendSize(unit, iob->io_Offset + iob->io_Length);
  354.         if (unit->Pos != iob->io_Offset)
  355.             Seek(unit->Fh, iob->io_Offset, -1);
  356.         iob->io_Actual = Read(unit->Fh, (char *)iob->io_Data, iob->io_Length);
  357.         if (iob->io_Actual == iob->io_Length)
  358.             unit->Pos = iob->io_Offset + iob->io_Actual;
  359.         else
  360.             unit->Pos = -1;
  361.         break;
  362.         case CMD_WRITE:
  363.         /*
  364.          *  This causes file to be closed/reopened after
  365.          *  formatting.
  366.          */
  367.         if (unit->Extended && unit->Fh) {
  368.             FlushCache();
  369.             Close(unit->Fh);
  370.             GetUnitName(unit - &DevBase->Unit[0], buf);
  371.             unit->Fh = Open(buf, 1005);
  372.             unit->Extended = 0;
  373.         }
  374.         /* fall through */
  375.         case TD_FORMAT:
  376.         if (unit->Fh == NULL)
  377.             break;
  378.  
  379.         if (iob->io_Offset > unit->Size) {
  380.             FlushCache();
  381.             ExtendSize(unit, iob->io_Offset);
  382.         }
  383.         if (CacheUnit != unit) {
  384.             FlushCache();
  385.             CacheUnit = unit;
  386.         }
  387.         if (unit->Pos != iob->io_Offset) {
  388.  
  389.             /*
  390.              *    Handle case where a CMD_WRITE modifies a previously
  391.              *    cached write (occurs with OFS *a lot*)
  392.              */
  393.  
  394.             if (CacheLen) {
  395.             long ci = CacheLen - (unit->Pos - iob->io_Offset);
  396.             if (ci >= 0 && ci + iob->io_Length <= CacheLen) {
  397. #ifdef DEBUG
  398.                 if (DbFH)
  399.                 Write(DbFH, "XBACK\n", 5);
  400. #endif
  401.                 iob->io_Actual = iob->io_Length;
  402.                 movmem(iob->io_Data, CacheBuf + ci, iob->io_Length);
  403.                 break;
  404.             }
  405.             }
  406.             FlushCache();
  407.             Seek(unit->Fh, iob->io_Offset, -1);
  408.         }
  409.  
  410.         if (CacheLen + iob->io_Length > sizeof(CacheBuf))
  411.             FlushCache();
  412.         if (CacheLen + iob->io_Length <= sizeof(CacheBuf)) {
  413.             iob->io_Actual = iob->io_Length;
  414.             unit->Pos = iob->io_Offset + iob->io_Actual;
  415.             movmem(iob->io_Data, CacheBuf + CacheLen, iob->io_Actual);
  416.             CacheLen += iob->io_Actual;
  417.         } else {
  418.             if (CacheLen)
  419.             FlushCache();
  420.             iob->io_Actual = Write(unit->Fh, (char *)iob->io_Data, iob->io_Length);
  421.             if (iob->io_Actual == iob->io_Length)
  422.             unit->Pos = iob->io_Offset + iob->io_Actual;
  423.             else
  424.             unit->Pos = -1;
  425.         }
  426.         break;
  427.         default:
  428.         break;
  429.         }
  430.  
  431.         if (notdone == 0)       /*  forbid before falling through */
  432.         Forbid();           /*  and esp before replying       */
  433.         ReplyMsg(&iob->io_Message);
  434.     }
  435. #ifdef DEBUG
  436.     if (DbFH == NULL)
  437.         DbFH = Open("con:0/0/320/100/Debug", 1006);
  438. #endif
  439.     }
  440. #ifdef DEBUG
  441.     if (DbFH)
  442.     Close(DbFH);
  443. #endif
  444.     /* fall through to exit */
  445. }
  446.  
  447. void
  448. GetUnitName(int unitnum, char *buf)
  449. {
  450. BPTR envfile;
  451. LONG envlen;
  452. BOOL gotit = FALSE;
  453.  
  454. /* New - see if ENVIRONMENT variable FMSUnit<n> exists (ex. FMSUnit2)
  455.  * containing full path to file.
  456.  */
  457. sprintf(buf,"ENV:FMSUnit%d",unitnum);
  458. if(envfile = Open(buf,MODE_OLDFILE))
  459.     {
  460.     envlen = Read(envfile,buf,128-2);
  461.     if(envlen >= 0)
  462.     {
  463.     gotit = TRUE;
  464.     buf[envlen] = '\0';
  465.         if(buf[envlen-1]=='\n') buf[envlen-1] = '\n';
  466.     }
  467.     Close(envfile);
  468.     }
  469. /* Fallback to old FMS:Unit<n> name */
  470. if(!gotit)
  471.     {
  472.     sprintf(buf, "FMS:Unit%d", unitnum);
  473.     }
  474. }
  475.  
  476. /*
  477.  *  Extend the file size in 4K chunks
  478.  */
  479.  
  480. void
  481. ExtendSize(unit, offset)
  482. NDUnit *unit;
  483. long offset;
  484. {
  485.     long pos;
  486.     char *buf = AllocMem(EXT_CHUNK, MEMF_CLEAR|MEMF_PUBLIC);
  487.  
  488.     if (buf) {
  489.     if (unit->Extended == 0)
  490.         unit->Extended = 1;
  491.     Seek(unit->Fh, 0L, 1);
  492.     pos = Seek(unit->Fh, 0L, 0);
  493.     while (pos < offset) {
  494.         if (Write(unit->Fh, buf, EXT_CHUNK) != EXT_CHUNK)
  495.         break;
  496.         pos += EXT_CHUNK;
  497.     }
  498.     FreeMem(buf, EXT_CHUNK);
  499.     unit->Pos = -1;     /*    unknown */
  500.     }
  501. }
  502.  
  503. /*
  504.  *  flush sequential write cache
  505.  */
  506.  
  507. void
  508. FlushCache()
  509. {
  510.     NDUnit *unit = CacheUnit;
  511.  
  512. #ifdef DEBUG
  513.     if (DbFH)
  514.     Write(DbFH, "FLUSH\n", 6);
  515. #endif
  516.  
  517.     if (CacheLen) {
  518.     Write(unit->Fh, CacheBuf, CacheLen);
  519.     CacheLen = 0;
  520.     }
  521. }
  522.